#include "UdxNodeSchema.h"
#include "UdxSchemaDescription.h"

namespace NGIS
{
	namespace Data
	{
		namespace Schema
		{
			CUdxNodeSchema::CUdxNodeSchema(IUdxNodeSchema* pParent, const char* pName, INodeDescription* pDescription) :mName(pName)
			{
				mExtension = 0;
				mParentNode = pParent;
				mDescription = pDescription;
				if (mParentNode) mParentNode->addRef();
				if (mDescription) mDescription->addRef();
			}

			CUdxNodeSchema::~CUdxNodeSchema()
			{
				if (mParentNode) mParentNode->release();
				if (mDescription) mDescription->release();
				for (int i=0; i<mChildNodes.size(); i++)
				{
					mChildNodes[i]->release();
				}
				mChildNodes.clear();
			}

			const char* CUdxNodeSchema::getName()
			{
				return mName.c_str();
			}

			INodeDescription* CUdxNodeSchema::getDescription()
			{
				return mDescription;
			}

			bool CUdxNodeSchema::modifyName(const char* pName)
			{
				std::string pNameStr = pName;
				if (mName == pNameStr) return false;
				mName = pName;
				return true;
			}

			IUdxNodeSchema* CUdxNodeSchema::getParentNode()
			{
				return mParentNode;
			}

			int CUdxNodeSchema::getChildNodeCount()
			{
				return mChildNodes.size();
			}

			IUdxNodeSchema* CUdxNodeSchema::getChildNode(int idx)
			{
				if (idx<0 || idx >=mChildNodes.size())
				{
					return NULL;
				}
				return mChildNodes[idx];
			}

			IUdxNodeSchema* CUdxNodeSchema::addChildNode(const char* pName, INodeDescription* pDescription)
			{
				ESchemaNodeType mType = mDescription->getKernelType();
				if (mType == EDTKT_INT ||
					mType == EDTKT_REAL ||
					mType == EDTKT_STRING ||
					mType == EDTKT_VECTOR2 ||
					mType == EDTKT_VECTOR3 ||
					mType == EDTKT_VECTOR4 ||
					mType == (EDTKT_INT|EDTKT_LIST) ||
					mType == (EDTKT_REAL|EDTKT_LIST) ||
					mType == (EDTKT_STRING|EDTKT_LIST) ||
					mType == (EDTKT_VECTOR2|EDTKT_LIST) ||
					mType == (EDTKT_VECTOR3|EDTKT_LIST) ||
					mType == (EDTKT_VECTOR4|EDTKT_LIST) )
				{
					return NULL;
				}
				else if (mType == EDTKT_LIST)
				{
					if (this->mChildNodes.size() >= 1)
						return NULL;
				}
				else if (mType == EDTKT_MAP)
				{
					if (this->mChildNodes.size() >= 2)
						return NULL;
				}
				else if (mType == EDTKT_TABLE)
				{
					bool isOK=false;
					ESchemaNodeType pType = pDescription->getKernelType();
					if (pType == (EDTKT_INT|EDTKT_LIST) ||
						pType == (EDTKT_REAL|EDTKT_LIST) ||
						pType == (EDTKT_STRING|EDTKT_LIST) ||
						pType == (EDTKT_VECTOR2|EDTKT_LIST) ||
						pType == (EDTKT_VECTOR3|EDTKT_LIST) ||
						pType == (EDTKT_VECTOR4|EDTKT_LIST))
					{
						isOK = true;
					}
					if (isOK==false) return NULL;
				}
				CUdxNodeSchema* pNode = new CUdxNodeSchema(this, pName, pDescription);
				this->mChildNodes.push_back(pNode);
				return pNode;
			}

			IUdxNodeSchema* CUdxNodeSchema::addChildNode(const char* pName, int pNodeType, const char* pNodeInfo)
			{
				CUdxSchemaDescription* pDescription = new CUdxSchemaDescription((ESchemaNodeType)pNodeType, pNodeInfo);
				IUdxNodeSchema* pNode = addChildNode(pName, pDescription);
				pDescription->release();
				return pNode;
			}

			bool CUdxNodeSchema::removeChildNode(IUdxNodeSchema* pNode)
			{
				std::vector<IUdxNodeSchema*>::iterator it = mChildNodes.begin();
				std::vector<IUdxNodeSchema*>::iterator end = mChildNodes.end();
				for (; it!=end; it++)
				{
					if (*it == pNode)
					{
						mChildNodes.erase(it);
						pNode->release();
						return true;
					}
				}
				return false;
			}

			bool CUdxNodeSchema::removeChildNode(int idx)
			{
				IUdxNodeSchema* pNode = getChildNode(idx);
				if (pNode==NULL)
				{
					return false;
				}
				std::vector<IUdxNodeSchema*>::iterator it = mChildNodes.begin();
				std::vector<IUdxNodeSchema*>::iterator end = mChildNodes.end();
				for (; it!=end; it++)
				{
					if (*it == pNode)
					{
						mChildNodes.erase(it);
						pNode->release();
						return true;
					}
				}
				return false;
			}

			void CUdxNodeSchema::setExtension(int flag)
			{
				mExtension = flag;
			}

			int CUdxNodeSchema::getExtension()
			{
				return mExtension;
			}

			bool CUdxNodeSchema::compareOther(IUdxNodeSchema* pNode)
			{
				if (compareNodeInfo(this, pNode) == false)
				{
					return false;
				}
				for (int iChild = 0; iChild < pNode->getChildNodeCount(); iChild++)
				{
					IUdxNodeSchema* tempNode1 = this->getChildNode(iChild);
					IUdxNodeSchema* tempNode2 = pNode->getChildNode(iChild);
					
					if (tempNode1->compareOther(tempNode2)==false)
					{
						return false;
					}
				}
				return true;
			}

			bool CUdxNodeSchema::compareNodeInfo(IUdxNodeSchema* pNode1, IUdxNodeSchema* pNode2)
			{
				int count1 = pNode1->getChildNodeCount();
				int count2 = pNode2->getChildNodeCount();
				if (count1 != count2)
				{
					return false;
				}
				if (pNode1->getDescription()->getKernelType() != pNode2->getDescription()->getKernelType())
				{
					return false;
				}
				std::string name1 = pNode1->getName();
				std::string name2 = pNode2->getName();
				if (name1 != name2)
				{
					return false;
				}
				std::string desc1 = pNode1->getDescription()->getNodeDescription();
				std::string desc2 = pNode2->getDescription()->getNodeDescription();
				if (desc1 != desc2)
				{
					return false;
				}
				std::string tag1 = pNode1->getDescription()->getConceptTag();
				std::string tag2 = pNode2->getDescription()->getConceptTag();
				if (tag1 != tag2)
				{
					return false;
				}
				tag1 = pNode1->getDescription()->getSpatialReferencefTag();
				tag2 = pNode2->getDescription()->getSpatialReferencefTag();
				if (tag1 != tag2)
				{
					return false;
				}
				tag1 = pNode1->getDescription()->getUnitTag();
				tag2 = pNode2->getDescription()->getUnitTag();
				if (tag1 != tag2)
				{
					return false;
				}
				tag1 = pNode1->getDescription()->getDimensionTag();
				tag2 = pNode2->getDescription()->getDimensionTag();
				if (tag1 != tag2)
				{
					return false;
				}
				tag1 = pNode1->getDescription()->getDataTemplateTag();
				tag2 = pNode2->getDescription()->getDataTemplateTag();
				if (tag1 != tag2)
				{
					return false;
				}
				return true;
			}

		}
	}
}